#pragma once

#include "Matrix.h"
#include "Calculus.h"

namespace XYF
{
    /**
     * @file RungeKutta.h
     * @author xingyifan
     * @date 2022-07-26 18:27
     *
     * @description: 定义时间网格和网格迭代器
     */

    using TimeGrid = std::vector<Vector>;                // 迭代网格，按照时间对应向量
    using GTimer = TimeGrid::iterator;                   // 网格迭代器
    using FuncXXt = std::function<Vector(Vector, Real)>; // 多元 + t 向量函数

    /**
     * @file RungeKutta.h
     * @author xingyifan
     * @date 2022-08-28 01:12
     *
     * @description: 基类 RungeKutta 方法
     */

    class RungeKutta
    {
    public:
        virtual GTimer shift(FuncXXt, GTimer) = 0;
    };

    /**
     * @file RungeKutta.h
     * @author xingyifan
     * @date 2022-07-27 16:13
     *
     * @description: 经典 RungeKutta 方法
     */

    class ClassicalRK : public RungeKutta
    {
    public:
        /**
         * @file RungeKutta.h
         * @author xingyifan
         * @date 2023-04-24 20:28
         *
         * @description: 通过时间步长构造
         */

        ClassicalRK(Real k);

        /**
         * @file RungeKutta.h
         * @author xingyifan
         * @date 2022-07-27 22:22
         *
         * @description: 显式方法，直接求解
         */

        GTimer shift(FuncXXt f, GTimer U);

    public:
        Matrix A_; // 系数矩阵
        Vector b_; // 加权
        Vector c_; // 节点

        Real t_; // 当前时间
        Real k_; // 时间步长
    };

    /**
     * @file RungeKutta.h
     * @author xingyifan
     * @date 2022-07-27 16:13
     *
     * @description: ESDI RK 方法
     */

    class ESDIRK : public RungeKutta
    {
    public:
        /**
         * @file RungeKutta.h
         * @author xingyifan
         * @date 2023-04-24 20:28
         *
         * @description: 通过时间步长构造
         */

        ESDIRK(Real k);

        /**
         * @file RungeKutta.h
         * @author xingyifan
         * @date 2022-07-27 22:41
         *
         * @description: 对角线隐式方法，对每个方程单独使用牛顿法求根
         */

        GTimer shift(FuncXXt f, GTimer U);

    public:
        Matrix A_; // 系数矩阵
        Vector b_; // 加权
        Vector c_; // 节点

        int s_;  // 级数
        Real t_; // 当前时间
        Real k_; // 时间步长
    };

    /**
     * @file RungeKutta.h
     * @author xingyifan
     * @date 2022-07-27 16:14
     *
     * @description: Gauss-Legendre 方法
     */

    class GaussLegendreRK : public RungeKutta
    {
    public:
        /**
         * @file RungeKutta.h
         * @author xingyifan
         * @date 2023-04-24 20:28
         *
         * @description: 通过阶数和时间步长构造
         */

        GaussLegendreRK(int s, Real k);

        /**
         * @file RungeKutta.h
         * @author xingyifan
         * @date 2022-07-27 23:01
         *
         * @description: 纯隐式方法，使用向量牛顿迭代法求解
         */

        GTimer shift(FuncXXt f, GTimer U);

    public:
        Matrix A_; // 系数矩阵
        Vector b_; // 加权
        Vector c_; // 节点

        int s_;  // 级数
        Real t_; // 当前时间
        Real k_; // 时间步长
    };

} // namespace XYF